package com.tbq.game.service.socket.netty

import io.netty.bootstrap.Bootstrap
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.timeout.IdleStateHandler
import java.util.concurrent.TimeUnit
/**
 * 建立一个 Netty 客户端
 * @param host     IP地址
 * @param port     端口
 * @param listener 监听器
 */
open class NettyClient(host: String?, port: Int, listener: NettyEventListener?) {
    private var channelFuture: ChannelFuture? = null
    private var channel: Channel? = null
    private var bootstrap: Bootstrap? = null
    private var eventLoopGroup: EventLoopGroup? = null
    companion object {
        var oldListener: NettyEventListener? = null
        private var HOST: String? = null
        private var PORT: Int = 0
        var isConnections = false    //是否正在连接中.
        val endFlag = "Δ"        //结束符号
        val keepaliveFlag = "➹"  //心跳过滤符号
        var reConnectTime = 10        //重连间隔
        var readerIdleTime = 20       //读取超时
        var writerIdleTime = 20       //写入超时
        var allIdleTime = 10          //全部超时
        /**
         * 重连 逻辑
         *
         * @param channel
         * @param e
         */
        fun loopConnect(channel: Channel?, e: Exception) {
            if (isConnections) return
            isConnections = false
            NettyLog.e(
                NettyLog.tag,
                "与服务器 " + HOST + ":" + PORT + " 断开连接, " + reConnectTime + " 秒后 " + channel?.id() + " 重连！",
                e
            )
            if (oldListener != null) oldListener?.onConnectError(e)
            channel?.eventLoop()?.schedule({
                if (!isConnections && !channel.isActive) {
                    NettyLog.e("重连任务" + channel.id() + "正在重连服务器。")
                    NettyClient(HOST, PORT, oldListener).connect()
                }
            }, reConnectTime.toLong(), TimeUnit.SECONDS)
        }
    }


    init {
        HOST = host
        PORT = port
        oldListener = listener
    }

    private fun initNettyClient() {
        eventLoopGroup = NioEventLoopGroup()
        bootstrap = Bootstrap()
        bootstrap?.group(eventLoopGroup)
        bootstrap?.channel(NioSocketChannel::class.java)
        bootstrap?.handler(ClientInitializer())
        //设置TCP协议的属性
        bootstrap?.option(ChannelOption.SO_KEEPALIVE, true)
        bootstrap?.option(ChannelOption.TCP_NODELAY, true)

        //        bootstrap.option(ChannelOption.SO_REUSEADDR, true);
        //        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        //        bootstrap.option(ChannelOption.SO_BACKLOG, 10000);
        //        bootstrap.option(ChannelOption.SO_RCVBUF, 1024);
        //        bootstrap.option(ChannelOption.SO_SNDBUF, 1024);
        //        bootstrap.option(ChannelOption.SO_TIMEOUT, 5000);
        //        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
    }

    /**
     * 开始连接服务器
     *
     * @return
     */
    fun connect(): NettyClient {
        if (oldListener != null) oldListener?.onConnections()
        if (channel != null)
            channel?.close()
        else
            initNettyClient()
        try {
            isConnections = true
            bootstrap?.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
            channelFuture = bootstrap?.connect(HOST, PORT)
            channelFuture?.addListener(channelFutureListener)
            channel = channelFuture?.awaitUninterruptibly()?.channel()
            channel?.pipeline()?.addLast("idleStateHandler", IdleStateHandler(2000, 2000, 2000, TimeUnit.MILLISECONDS))
            NettyLog.e("建立 Socket 通道：$HOST:$PORT")
        } catch (e: Exception) {
            NettyLog.e(NettyLog.tag, "Socket通道建立出错：$HOST:$PORT", e)
            loopConnect(channelFuture?.channel(), e)
        }

        return this
    }

    internal var channelFutureListener: ChannelFutureListener = ChannelFutureListener { f ->
        if (f.isSuccess) {
            NettyLog.e("接服务器成功")
            isConnections = false
            listener?.onConnectSuccess()
        } else {
            loopConnect(f.channel(), Exception("网络不稳定，和服务器连接中断！"))
        }
    }


}